#include "BDReceiver.h"
#include "google/protobuf/message.h"

BDReceiver::BDReceiver(std::string address)
	: m_bStartFlag(true)
	, m_zmq(address)
{
	
}


BDReceiver::~BDReceiver()
{
}

void BDReceiver::ReceiveMessage()
{
	unsigned char buffer[1024];
	MessageType type;
	int length = m_zmq.RecvMsg(buffer, 1024);
	if (length < 0) {
		return;
	}
	google::protobuf::Message* message = Decode(buffer, length, type);
	if (message == NULL) {
		return;
	}
	std::map<MessageType, std::vector<std::function<void(void* ptr)>>>::iterator it = m_mapCallback.find(type);
	if (it == m_mapCallback.end()) {
		return;
	}
	std::vector<std::function<void(void* ptr)>>& callbackVector = it->second;
	std::vector<std::function<void(void* ptr)>>::iterator itVector = callbackVector.begin();
	for (; itVector != callbackVector.end(); ++itVector) {
		(*itVector)((void*)message);
	}
	delete message;
	message = NULL;
}

void BDReceiver::RegisterCallback(MessageType type, std::function<void(void*)> callback)
{
	m_mapCallback[type].push_back(callback);
}

void* BDReceiver::Run(void* data)
{
	m_zmq.Init();
	while (m_bStartFlag) {
		ReceiveMessage();
	}
	m_zmq.DeInit();
	return NULL;
}

google::protobuf::Message* BDReceiver::Decode(void* buffer, unsigned int length, MessageType& type)
{
	google::protobuf::Message* result = NULL;
	char* current = (char*)buffer;

	unsigned int name_len = *((unsigned int*)current);
	current += sizeof(unsigned int);

	std::string name_str(current, current + name_len);
	current += name_len;

	unsigned int type_val = *((unsigned int*)current);
	current += sizeof(unsigned int);

	unsigned int message_len = length - (current - (char*)buffer);

	google::protobuf::Message* message = CreateMessage(name_str);
	if (message) {
		if (message->ParseFromArray(current, message_len)) {
			result = message;
			type = static_cast<MessageType>(type_val);
		}
		else {
			delete message;
			message = NULL;
		}
	}
	return result;
}

google::protobuf::Message* BDReceiver::CreateMessage(const std::string& type_name)
{
	google::protobuf::Message* message = NULL;
	const google::protobuf::Descriptor* descriptor =
		google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(type_name);
	if (descriptor)
	{
		const google::protobuf::Message* prototype =
			google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
		if (prototype)
		{
			message = prototype->New();
		}
	}
	return message;
}

void BDReceiver::Stop()
{
	m_bStartFlag = false;
}